#include "api/include/ctc_api.h"
#include "api/include/ctcs_api.h"
#include "ctc_app_cfg.h"
#include "app_usr.h"
#include "ctc_app_isr.h"
#include "ctc_app.h"
#include "ctc_cli.h"
#include "ctc_cli_common.h"
#include "ctc_app_warmboot.h"
#include "ctc_app_packet.h"
#include "common/include/ctc_pmem.h"

/*the datapath is apply to centec's demo borad*/
#ifdef SDK_IN_USERMODE
#include <sys/mman.h>

#endif

extern int32 g_error_on;
extern int32 ctc_master_cli(int32 ctc_shell_mode);
extern int32 ctc_cli_read(int32 ctc_shell_mode);
extern int32 ctc_app_cli_init(void);
ctc_app_master_t g_ctc_app_master = {0};


int32
ctc_app_get_lchip_id(uint8 gchip, uint8* lchip)
{
    uint8 ldev = 0;
    uint8 chip_type = CTC_CHIP_NONE;

    if (NULL == lchip)
    {
        return -1;
    }

    for (ldev = 0; ldev < g_ctc_app_master.lchip_num; ldev++)
    {
        chip_type = g_ctc_app_master.ctcs_api_en?ctcs_get_chip_type(ldev):ctc_get_chip_type();
        if (CTC_CHIP_NONE == chip_type)
        {
            continue;
        }
        if (gchip == g_ctc_app_master.gchip_id[ldev])
        {
            *lchip = ldev;
            return 0;
        }
    }

    return -1;
}

int32
ctc_app_sample_init(void)
{
    int32 ret = 0;
    uint8 ldev = 0;

    if (0 == g_ctc_app_master.ctcs_api_en)
    {
        /*call ctc api functions */
        ret = ctc_app_isr_init();
        if (ret != 0)
        {
            CTC_APP_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "ctc_app_isr_init failed:%s@%d \n",  __FUNCTION__, __LINE__);
            return ret;
        }
    }
    else
    {
        /*call ctcs api functions for per chip operation*/
        for (ldev = 0; ldev < g_ctc_app_master.lchip_num; ldev++)
        {
            if (CTC_CHIP_NONE == ctcs_get_chip_type(ldev))
            {
                continue;
            }
            ret = ctcs_app_isr_init(ldev);
            if (ret != 0)
            {
                CTC_APP_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "ctcs_app_isr_init failed:%s@%d \n",  __FUNCTION__, __LINE__);
                return ret;
            }
        }
    }

    ret = ctc_app_packet_eth_init();
    if (ret != 0)
    {
        CTC_APP_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "ctc_app_packet_eth_init failed:%s@%d \n",  __FUNCTION__, __LINE__);
        return ret;
    }


	for (ldev = 0; ldev < g_ctc_app_master.lchip_num; ldev++)
    {
        if (g_ctc_app_master.ctcs_api_en && CTC_CHIP_NONE == ctcs_get_chip_type(ldev))
        {
            continue;
        }
        ret = ctc_app_index_init(g_ctc_app_master.gchip_id[ldev]);
       if (ret != 0)
       {
           CTC_APP_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "ctc_app_index_init failed:%s@%d \n",  __FUNCTION__, __LINE__);
           return ret;
       }
 	}


    return ret;
}

/* init pmem for warmboot */
int32
ctc_app_wb_pmem_init(uint8 ldev, ctc_wb_api_t* wb_api, ctc_init_cfg_t *p_init_config )
{
    int32 ret = 0;
#ifdef SDK_IN_USERMODE
    ctc_pmem_cfg_t  pmem_cfg;

    wb_api->enable = g_ctc_app_master.wb_enable;
    wb_api->reloading = g_ctc_app_master.wb_enable && g_ctc_app_master.wb_reloading;
    wb_api->mode = g_ctc_app_master.wb_mode;
    wb_api->init = &ctc_app_wb_init;
    wb_api->init_done = &ctc_app_wb_init_done;
    wb_api->sync = &ctc_app_wb_sync;
    wb_api->sync_done = &ctc_app_wb_sync_done;
    wb_api->add_entry = &ctc_app_wb_add_entry;
    wb_api->query_entry = &ctc_app_wb_query_entry;
    wb_api->size = 0;
    pmem_cfg.create = !wb_api->reloading;
    pmem_cfg.size = 0;
    pmem_cfg.type = 0;
    if(p_init_config->p_chip_cfg == NULL)
    {
        return CTC_E_UNEXPECT;
    }
    if(wb_api->mode && p_init_config->p_chip_cfg->wb_dm_mem_size)
    {
        pmem_cfg.size = p_init_config->p_chip_cfg->wb_dm_mem_size ;
        wb_api->size = p_init_config->p_chip_cfg->wb_dm_mem_size;
    }
	sal_sprintf(pmem_cfg.file_name,"ctc_pmem%d",ldev);
	wb_api->start_addr = ctc_pmem_init(ldev, &pmem_cfg);
	p_init_config->p_wb_config = wb_api;

 #else
    wb_api->mode = 0;
    wb_api->size  = 0;
#endif
    return ret;
}

void
ctc_app_sdb_pmem_init(uint8 lchip, ctc_init_cfg_t *p_init_config, ctc_wb_api_t* wb_api)
{
#ifdef SDK_IN_USERMODE
    ctc_pmem_cfg_t  sdb_pmem_cfg;

    sdb_pmem_cfg.create = !wb_api->reloading;
    sdb_pmem_cfg.size = 0;
    sdb_pmem_cfg.type = 1;

    if(p_init_config->p_chip_cfg == NULL)
    {
        return;
    }

    /* init pmem for sdb */
    if (p_init_config->p_chip_cfg->sdb_mem_size && p_init_config->p_chip_cfg->sdb_en)
    {
     sdb_pmem_cfg.size = p_init_config->p_chip_cfg->sdb_mem_size;
    }
    sal_sprintf(sdb_pmem_cfg.file_name,"ctc_sdb_pmem%d", lchip);
    p_init_config->p_chip_cfg->sdb_mem_addr = ctc_pmem_init(lchip, &sdb_pmem_cfg);
 #else
    if(p_init_config->p_chip_cfg)
    {
       p_init_config->p_chip_cfg->sdb_mem_size = 0;
       p_init_config->p_chip_cfg->sdb_mem_addr = 0;
    }
#endif
    return;
}

void
ctc_app_sdb_addr_init(uint8 lchip, uint8 sdb_en, uintptr start_addr, uintptr* addr, uint32* size)
{
    ctc_pmem_cfg_t  pmem_cfg;

    if (!g_ctc_app_master.wb_enable && sdb_en)
    {
        pmem_cfg.size = CTC_APP_SDB_MEM_SIZE;
        pmem_cfg.create = sdb_en;
        sal_sprintf(pmem_cfg.file_name,"ctcsdb%d",lchip);
        *addr = ctc_pmem_init(lchip, &pmem_cfg);
        *size = CTC_APP_SDB_MEM_SIZE;
    }
    else if (start_addr)/*use ctcwbX*/
    {
        *addr = start_addr + CTC_APP_WB_APPID_MEM_SIZE;
        *size = CTC_APP_SDB_MEM_SIZE;
    }
}

int32
ctc_app_sdk_init(ctc_init_cfg_t* p_init_config)
{
    int32 ret = 0;
    ctc_init_cfg_t init_config;
    uint8 ldev = 0;
    ctc_wb_api_t wb_api;
    sal_systime_t tv1,tv2;

    /* init mem module */
    ret = mem_mgr_init();
    if (ret != 0)
    {
        CTC_APP_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,"mem_mgr_init failed:%s@%d \n",  __FUNCTION__, __LINE__);
        return ret;
    }

    sal_memset(&wb_api, 0, sizeof(ctc_wb_api_t));
    sal_memset(&init_config,0,sizeof(ctc_init_cfg_t));

    g_error_on = 0;

    /* init debug module */
    ret = ctc_debug_init();
    if (ret != 0)
    {
        CTC_APP_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,"ctc_debug_init failed:%s@%d \n",  __FUNCTION__, __LINE__);
        goto EXIT;
    }

    /* init sal module */
    ret = sal_init();
    if (ret != 0)
    {
        CTC_APP_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,"sal_init failed:%s@%d \n",  __FUNCTION__, __LINE__);
        goto EXIT;
    }
    sal_gettime(&tv1);


    /* init sdk */
    if (0 == g_ctc_app_master.ctcs_api_en)
    {
        if (p_init_config != NULL)
        {
            sal_memcpy(&init_config, p_init_config, sizeof(ctc_init_cfg_t));
        }
        else
        {
            ret = ctc_app_parse_config(ldev, &init_config);
            if (ret != 0)
            {
                CTC_APP_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "ctc_app_parse_config failed:%s@%d \n",  __FUNCTION__, __LINE__);
                goto EXIT;
            }
            if (0 == g_ctc_app_master.ctcs_api_en)
            {
                for (ldev = 1; ldev < init_config.local_chip_num; ldev++)
                {
                    sal_memcpy(init_config.p_datapath_cfg + ldev, init_config.p_datapath_cfg, sizeof(ctc_datapath_global_cfg_t));
                }
            }
        }
    }
    
    /* init sdk */
    if (0 == g_ctc_app_master.ctcs_api_en)
    {
       /*use ctcs api functions for per chip operation*/
        for (ldev = 0; ldev < init_config.local_chip_num; ldev++)
        {
            ret = ctc_app_wb_pmem_init(ldev, &wb_api, &init_config);/*arctic not support in ctc_api mode*/      
            if (ret != 0)
            {
                CTC_APP_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "ctc_wb_init failed:%s@%d \n",  __FUNCTION__, __LINE__);
                goto EXIT;
            }
			init_config.p_wb_config = &wb_api;

            /* init sdb pmem */
            ctc_app_sdb_pmem_init(ldev, &init_config, &wb_api);
        }

        g_ctc_app_master.lchip_num = init_config.local_chip_num;
        sal_memcpy(g_ctc_app_master.gchip_id, init_config.gchip, sizeof(uint8)*CTC_MAX_LOCAL_DEV_NUM);

        /*use ctc api functions */
        ret = ctc_sdk_init(&init_config);
        if (ret != 0)
        {
            CTC_APP_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "ctc_sdk_init failed:%s@%d \n",  __FUNCTION__, __LINE__);
            goto EXIT;
        }
    }
    else
    {
        /*use ctcs api functions for per chip operation*/
        for (ldev = 0; ldev< CTC_MAX_LOCAL_DEV_NUM; ldev++)
        {
            /* get config info */
            if(p_init_config != NULL)
            {
                sal_memcpy(&init_config, p_init_config, sizeof(ctc_init_cfg_t));
            }
            else
            {
                ret = ctc_app_parse_config(ldev, &init_config);
                if (ret != 0)
                {
                    CTC_APP_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "ctc_app_parse_config failed:%s@%d \n",  __FUNCTION__, __LINE__);
                    goto EXIT;
                }
            }

            if (init_config.local_chip_num == 0)
            {
                CTC_APP_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "local_chip_num failed:%s@%d \n",  __FUNCTION__, __LINE__);
                ret = CTC_E_INVALID_CHIP_ID;
                goto EXIT;
            }
            
            if (ldev >= init_config.local_chip_num)
            {
                break;
            }

            ret = ctc_app_wb_pmem_init(ldev, &wb_api, &init_config);
            if (ret != 0)
            {
                CTC_APP_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "ctc_wb_init failed:%s@%d \n",  __FUNCTION__, __LINE__);
                goto EXIT;
            }
			init_config.p_wb_config = &wb_api;

            /* init sdb pmem */
            ctc_app_sdb_pmem_init(ldev, &init_config, &wb_api);
            sal_memcpy(g_ctc_app_master.gchip_id, init_config.gchip, sizeof(uint8)*CTC_MAX_LOCAL_DEV_NUM);

            g_ctc_app_master.lchip_num = init_config.local_chip_num;

            ret = ctcs_sdk_init(ldev, &init_config);
            if (ret != 0)
            {
                CTC_APP_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "ctcs_sdk_init(ldev:%d) failed:%s@%d \n", ldev,  __FUNCTION__, __LINE__);
                goto EXIT;
            }
        }
    }
    sal_gettime(&tv2);
    if(tv2.tv_usec >= tv1.tv_usec)
    {
        ctc_cli_out_basic("USED  TIME:[%10u s:%3u ms]\n", tv2.tv_sec - tv1.tv_sec, (tv2.tv_usec - tv1.tv_usec)/1000);
    }
    else
    {
        ctc_cli_out_basic("USED  TIME:[%10u s:%3u ms]\n", tv2.tv_sec - tv1.tv_sec - 1, (tv2.tv_usec + 1000000 - tv1.tv_usec)/1000);
    }
EXIT:
    ctc_app_free_init_param(&init_config);

    g_error_on = 0;

    return ret;
}

int32
ctc_app_sdk_deinit(void)
{
    int32 ret = 0;
    uint8 ldev = 0;

    if (0 == g_ctc_app_master.ctcs_api_en)
    {
        ret = ctc_sdk_deinit();
    }
    else
    {
        for (ldev = 0; ldev < CTC_MAX_LOCAL_DEV_NUM; ldev++)
        {
            if (CTC_CHIP_NONE == ctcs_get_chip_type(ldev))
            {
                continue;
            }
            ret = ctcs_sdk_deinit(ldev);
			ctc_pmem_deinit(ldev);
        }
    }
    g_ctc_app_master.wb_reloading = 0;
    ctc_debug_deinit();
    return ret;
}

/**
 @brief The sample code for initialize SDK

 @param[in] ctc_shell_mode  mode 0, get commands from screen.
                            mode 1, C/S mode, client and server communicate by socket/netlink. The shell server start up with SDK, and the client is ctc_shell.
                            mode 2, user define mode, input commands by ctc_vti_cmd_input() and output result to user by ctc_vti_cmd_output_register().

 @param[in] ctcs_api_en   ctc api mode or ctcs api mode

 @remark  Refer to SDK PG and APP for detail description

 @return CTC_E_XXX

*/

int32
userinit(uint8 ctc_shell_mode, uint8 ctcs_api_en, void* p_init_config)
{
    int32 ret = 0;
    ctc_init_cfg_t* user_init_config = (ctc_init_cfg_t*)p_init_config;
    g_ctc_app_master.ctcs_api_en = ctcs_api_en;

    ret = ctc_app_sdk_init(user_init_config);
    if (ret != 0)
    {
        CTC_APP_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "ctc_app_sdk_init failed, error code is %d \n", ret);
        return ret;
    }

    /* cli used for sdk start_up, for example serdes ffe typical cfg */
    ret = ctc_app_usr_init();
    if (ret != 0)
    {
        CTC_APP_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "app_usr_init failed, error code is %d \n", ret);
        return ret;
    }
    ret = ctc_app_sample_init();
    if (ret != 0)
    {
        CTC_APP_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "ctc_app_sample_init failed, error code is %d \n", ret);
        return ret;
    }

#ifndef EMULATION_ENV
    ret = ctc_master_cli(ctc_shell_mode);
    if (ret != 0)
    {
        CTC_APP_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\nctc_cli_init failed. \nExit...... \n");
        return ret;
    }
#endif

#ifdef _SAL_LINUX_UM
    ctc_app_cli_init();
#endif

#ifdef CTC_PHY_EN
    extern int32 phy_init(uint8 load_mode, const char *pathname);
    ret = phy_init(0x22, NULL);
    if (ret)
    {
        CTC_APP_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "phy_init failed:%s@%d\n", __FUNCTION__, __LINE__);
        return ret;
    }
#endif

    if (ctc_shell_mode < 2)
    {
        ctc_cli_read(ctc_shell_mode);
    }
    return 0;
}
CTC_EXPORT_SYMBOL(userinit);

